package web

import (
	intrv1 "booksmart/book/api/proto/gen/intr/v1"
	rewardv1 "booksmart/book/api/proto/gen/reward/v1"
	"booksmart/book/internal/domain"
	"booksmart/book/internal/service"
	"booksmart/book/pkg/ginx"
	logger2 "booksmart/book/pkg/logger"
	"fmt"
	"github.com/ecodeclub/ekit/slice"
	"github.com/gin-gonic/gin"
	"net/http"
	"strconv"
	"time"
)

//var _ handler = (*ArticleHandler)(nil)

type ArticleHandler struct {
	svc       service.ArticleService
	l         logger2.LoggerV1
	intrSvc   intrv1.InteractiveServiceClient
	rewardSvc rewardv1.RewardServiceClient
	biz       string
}

func NewArticleHandler(svc service.ArticleService, l logger2.LoggerV1, intrSvc intrv1.InteractiveServiceClient) *ArticleHandler {
	return &ArticleHandler{svc: svc, l: l, intrSvc: intrSvc}
}

func (h *ArticleHandler) RegisterRoutes(server *gin.Engine) {
	g := server.Group("/articles")
	g.POST("/edit", ginx.WrapBodyAndToken[ArticleReq, domain.Author](h.Edit))
	g.POST("/publish", ginx.WrapBodyAndToken[ArticleReq, domain.Author](h.Publish))
	g.POST("/withdraw", ginx.WrapBodyAndToken[ArticleReq, domain.Author](h.Withdraw))
	g.POST("/list", ginx.WrapBodyAndToken[ListReq, domain.Author](h.List))
	g.GET("/detail/:id", ginx.WrapToken[domain.Author](h.Detail))
	g.GET("/Like/", ginx.WrapBodyAndToken[LikeReq, domain.Author](h.Like))
	g.POST("/get/", ginx.WrapBodyAndToken[LikeReq, domain.Author](h.Get))
	g.POST("/getByIds/", ginx.WrapBodyAndToken[LikeReq, domain.Author](h.GetByIds))

	pubGroup := server.Group("/pub")
	pubGroup.GET("/:id", h.PubDetail)
	pubGroup.POST("/reward", ginx.WrapBodyAndToken[RewardReq,
		domain.Author](h.Reward))
}

func (h *ArticleHandler) Reward(ctx *gin.Context, req RewardReq, uc domain.Author) (ginx.Status, error) {
	art, err := h.svc.GetPublishedById(ctx, req.Id, uc.Id)
	if err != nil {
		return ginx.Status{}, err
	}
	// 我要在这里实现打赏
	// 拿到一个打赏的二维码
	// 我不是直接调用支付，而是调用打赏
	// 打赏什么东西，谁打赏，打赏多少钱？
	resp, err := h.rewardSvc.PreReward(ctx, &rewardv1.PreRewardRequest{
		Biz:   "article",
		BizId: req.Id,
		Uid:   uc.Id,
		Amt:   req.Amount,
		// 创作者是谁？
		TargetUid: art.Author.Id,
		// 这个地方用作者呢？还是用标题呢？
		// 作者写得好
		BizName: art.Title,
	})
	return ginx.Status{
		Data: map[string]any{
			"codeURL": resp.CodeUrl,
			// 代表的是这一次的打赏
			"rid": resp.Rid,
		},
	}, nil
}

func (h *ArticleHandler) GetByIds(ctx *gin.Context, req LikeReq, au domain.Author) (ginx.Status, error) {
	resp, err := h.intrSvc.GetByIds(ctx, &intrv1.GetByIdsRequest{
		Biz: h.biz, BizIds: []int64{1},
	})
	if err != nil {
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	return Status{Msg: "OK", Data: resp.Intrs}, nil
}

func (h *ArticleHandler) Get(ctx *gin.Context, req LikeReq, au domain.Author) (ginx.Status, error) {
	resp, err := h.intrSvc.Get(ctx, &intrv1.GetRequest{
		Biz: h.biz, BizId: req.Id, Uid: au.Id,
	})
	if err != nil {
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	return Status{Msg: "OK", Data: resp.Intr}, nil
}

func (h *ArticleHandler) Like(ctx *gin.Context, req LikeReq, au domain.Author) (ginx.Status, error) {
	var err error
	if req.Like {
		_, err = h.intrSvc.Like(ctx, &intrv1.LikeRequest{
			Biz: h.biz, BizId: req.Id, Uid: au.Id,
		})
	} else {
		_, err = h.intrSvc.CancelLike(ctx, &intrv1.CancelLikeRequest{Biz: h.biz, BizId: req.Id, Uid: au.Id})
	}
	if err != nil {
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	return Status{Msg: "OK"}, nil
}

func (h *ArticleHandler) PubDetail(context *gin.Context) {

}

func (h *ArticleHandler) Detail(ctx *gin.Context, authorInfo domain.Author) (ginx.Status, error) {
	idstr := ctx.Param("id")
	id, err := strconv.ParseInt(idstr, 10, 64)
	if err != nil {
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	art, err := h.svc.GetById(ctx, id)
	if err != nil {
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	if art.Author.Id != authorInfo.Id {
		h.l.Error("非法访问文章，创作者ID 不匹配", logger2.Int64("uid", authorInfo.Id))
		return Status{Code: 5, Msg: "输入有误"}, fmt.Errorf("非法访问文章，创作者ID 不匹配%d", authorInfo.Id)
	}

	return Status{Data: ArticleVo{
		Id:      art.Id,
		Title:   art.Title,
		Content: art.Abstract(),
		Status:  art.Status.ToUint8(),
		Ctime:   art.Ctime.Format(time.DateTime),
		Utime:   art.Utime.Format(time.DateTime),
	}}, nil
}

func (h *ArticleHandler) List(ctx *gin.Context, req ListReq, authorInfo domain.Author) (ginx.Status, error) {
	res, err := h.svc.List(ctx, authorInfo.Id, req.Offset, req.Limit)
	if err != nil {
		return Status{Code: 5, Msg: "系統错误"}, err
	}
	//在列表页面,不显示全文，只显示一个摘要，
	return Status{Data: slice.Map[domain.Article, ArticleVo](res, func(idx int, src domain.Article) ArticleVo {
		return ArticleVo{
			Id:      src.Id,
			Title:   src.Title,
			Content: src.Abstract(),
			Status:  src.Status.ToUint8(),
			Ctime:   src.Ctime.Format(time.DateTime),
			Utime:   src.Utime.Format(time.DateTime),
		}
	})}, nil
}

func (h *ArticleHandler) Withdraw(ctx *gin.Context, req ArticleReq, authorInfo domain.Author) (ginx.Status, error) {
	err := h.svc.Withdraw(ctx, domain.Article{
		Id: req.Id,
		Author: domain.Author{
			Id: authorInfo.Id,
		},
	})
	if err != nil {
		ctx.JSON(http.StatusOK, Status{
			Code: 5,
			Msg:  "系统错误",
		})
		h.l.Error("发表帖子失败", logger2.Error(err))
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	//ctx.JSON(http.StatusOK, Status{
	//	Msg: "OK",
	//})
	return Status{Msg: "OK"}, nil

}

func (h *ArticleHandler) Publish(ctx *gin.Context, req ArticleReq, authorInfo domain.Author) (ginx.Status, error) {
	id, err := h.svc.Publish(ctx, req.toDomain(authorInfo.Id))
	if err != nil {
		//ctx.JSON(http.StatusOK, Status{
		//	Code: 5,
		//	Msg:  "系统错误",
		//})
		h.l.Error("发表帖子失败", logger2.Error(err))
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	return Status{Msg: "OK", Data: id}, nil
}

func (h *ArticleHandler) Edit(ctx *gin.Context, req ArticleReq, authorInfo domain.Author) (ginx.Status, error) {
	id, err := h.svc.Save(ctx, req.toDomain(authorInfo.Id))
	if err != nil {
		h.l.Error("保存失败", logger2.Error(err))
		return Status{Code: 5, Msg: "系统错误"}, err
	}
	return Status{Msg: "OK", Data: id}, nil

}
